package com.huitone.smspfm.task;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.swing.text.html.parser.Entity;

import com.bin.common.utils.PingIpUtils;
import com.bin.common.utils.StringUtils;
import com.huitone.smspfm.context.utils.ContextUtils;
import com.huitone.smspfm.core.config.AppStaticConfigs;
import com.huitone.smspfm.core.waterpipe.client.IGateLink;
import com.huitone.smspfm.core.waterpipe.client.impl.SimpleGateLink;
import com.huitone.smspfm.core.wransms.SmsWarnRecvMessage;
import com.huitone.smspfm.core.wransms.WranSmsSocketTask;
import com.huitone.smspfm.dao.oracle.GateSwitchDao;
import com.huitone.smspfm.dao.oracle.entity.WarnRecv;
import com.huitone.smspfm.logger.ExtLogger;

public class GatewayAutoSwitchTask extends Thread {
	
	private final static ExtLogger logger = ExtLogger.create(GatewayAutoSwitchTask.class);
	

	private boolean keepGoing = true;
	
	private int excutePoolSize = 5;
	
	private int excuteInterval = 1 * 20 * 1000;
	
	private int pingErrorNum = 3;
	
//	public static Map<String,Boolean> gateNetworkMap = new HashMap<String, Boolean>();
	
	//需要进行线路切换的列表 [linkID:lineType]
	public static ConcurrentLinkedQueue<String> gatewaySwitchQueue = new ConcurrentLinkedQueue<String>();
	
	//PING 中进行连接状态查询  [linkID:lineType:ip]
	private static ConcurrentLinkedQueue<String> pingQueue = new ConcurrentLinkedQueue<String>();
	
	private static Map<String,Integer> pingResult = new HashMap<String, Integer>();
	
	private PingTask pingTask = null;
	
	public class GateNetworkStatus {
		private String lineType;
		private boolean specialNetwork;
		private boolean internetNetwork;
		public GateNetworkStatus(){specialNetwork = false;internetNetwork=false;}
		public boolean isSpecialNetwork() { return specialNetwork;}
		public void setSpecialNetwork(boolean specialNetwork) {this.specialNetwork = specialNetwork;}
		public boolean isInternetNetwork() {return internetNetwork;}
		public void setInternetNetwork(boolean internetNetwork) {this.internetNetwork = internetNetwork;}		
		public boolean isNetworkStatus(){return isInternetNetwork() || isSpecialNetwork();}
		public void setNetworkStatus(boolean status){ setInternetNetwork(status); setSpecialNetwork(status);}
	}
	
	private ExecutorService gatewayPool = new ThreadPoolExecutor(excutePoolSize, 
			excutePoolSize, 
			1L, 
			TimeUnit.MINUTES, 
			new ArrayBlockingQueue<>(excutePoolSize * 2),
			new RejectedExecutionHandler() {
		
		@Override
		public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
			boolean offer = false;
			while(!executor.isShutdown() && !offer) {
				offer = executor.getQueue().offer(r);
				if (!offer) {
					try {
						TimeUnit.MILLISECONDS.sleep(10);
					} catch (InterruptedException e) {}
				}
			}
		}
	});
	
	@Override
	public void run() {
		logger.info("网关切换线程正在启动……");
		startPingTask();
		while (keepGoing && ! this.isInterrupted()){
			try{
				if (AppStaticConfigs.gateAutoSwitchFlag) {
					// scan gateway status
					scanGatewayNetwork();
				}
				
			} catch (Exception e){
				e.printStackTrace();
				logger.error("task exception!  ex: "+e.getMessage());
			}
			
			try {
				Thread.sleep(excuteInterval);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		logger.info("网关切换线程正在退出……");
	}
	
	private class PingTask extends Thread{

		@Override
		public void run() {

			while(keepGoing && ! this.isInterrupted()){
				try{
					if( ! pingQueue.isEmpty()){
						
						gatewayPool.execute(new Runnable() {
							
							@Override
							public void run() {
								String queueStr = pingQueue.poll();
								if(queueStr == null){
									return;
								}
								List<String> strList = StringUtils.splitToList(queueStr, ":");
								if(strList.size() < 3){
									logger.error("PING queue DATA ERROR : SIZE < 3");
									return;
								}
								String linkId = strList.get(0);
								String linkType = strList.get(1);
								String ip = strList.get(2);
								boolean ping = PingIpUtils.ping(ip, 4, 50);
								if(ping){
									if(pingResult.containsKey(queueStr)){
										pingResult.remove(queueStr);
									}
								} else {
									if(pingResult.containsKey(queueStr)){
										int val = pingResult.get(queueStr);
										if(val >= pingErrorNum){
											gatewaySwitchQueue.offer(linkId+":"+linkType);
											pingResult.remove(queueStr);
										} else {
											pingResult.put(queueStr, val+1);
										}
									} else {
										pingResult.put(queueStr, 1);
									}
								}	
							}
						});
					}
					
					if(! gatewaySwitchQueue.isEmpty()){
						gatewayPool.execute(new Runnable() {
							
							@Override
							public void run() {
								String gatewayStr = gatewaySwitchQueue.poll();
								if(gatewayStr == null){
									return;
								}
								List<String> listStr = StringUtils.splitToStringList(gatewayStr, ":");
								if(listStr.size() < 2){
									logger.error("PING Gateway Switch Queue DATA ERROR : SIZE < 2");
									return;
								}
								String linkId = listStr.get(0);
								String lineType = listStr.get(1);
								String ip = null;
								if(listStr.size() >= 3){
									ip = listStr.get(2);
								}
								//切换网络
								
								if(ip == null){
									//直接写数据库
									switchGatewayNetwork(linkId,lineType,ip);
								} else {
									boolean ping = PingIpUtils.ping(ip, 4, 50);
									if(ping){
										switchGatewayNetwork(linkId,lineType,ip);
										
									} else {
										logger.error("网关切换失败，双线网络均不可达  key:" + gatewayStr);
									}	
								}
								
							}
						});
					}
				}catch (Exception e){}
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {}
			}
			
			
		
		}

		@Override
		public void destroy() {
			this.interrupt();
		}
		
	}
	
	private void stopPingTask(){
		if(pingTask != null){
			pingTask.destroy();
			pingTask = null;
		}
	}
	
	//处理PING命令
	private void startPingTask(){
		if(pingTask == null || ! pingTask.isAlive()){
			pingTask = new PingTask();
			pingTask.start();
		}
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				while(keepGoing){
//					try{
//						if( ! pingQueue.isEmpty()){
//							
//							gatewayPool.execute(new Runnable() {
//								
//								@Override
//								public void run() {
//									String queueStr = pingQueue.poll();
//									if(queueStr == null){
//										return;
//									}
//									List<String> strList = StringUtils.splitToList(queueStr, ":");
//									if(strList.size() < 3){
//										logger.error("PING queue DATA ERROR : SIZE < 3");
//										return;
//									}
//									String linkId = strList.get(0);
//									String linkType = strList.get(1);
//									String ip = strList.get(2);
//									boolean ping = PingIpUtils.ping(ip, 4, 50);
//									if(ping){
//										if(pingResult.containsKey(queueStr)){
//											pingResult.remove(queueStr);
//										}
//									} else {
//										if(pingResult.containsKey(queueStr)){
//											int val = pingResult.get(queueStr);
//											if(val >= pingErrorNum){
//												gatewaySwitchQueue.offer(linkId+":"+linkType);
//												pingResult.remove(queueStr);
//											} else {
//												pingResult.put(queueStr, val+1);
//											}
//										} else {
//											pingResult.put(queueStr, 1);
//										}
//									}	
//								}
//							});
//						}
//						
//						if(! gatewaySwitchQueue.isEmpty()){
//							gatewayPool.execute(new Runnable() {
//								
//								@Override
//								public void run() {
//									String gatewayStr = gatewaySwitchQueue.poll();
//									if(gatewayStr == null){
//										return;
//									}
//									List<String> listStr = StringUtils.splitToStringList(gatewayStr, ":");
//									if(listStr.size() < 2){
//										logger.error("PING Gateway Switch Queue DATA ERROR : SIZE < 2");
//										return;
//									}
//									String linkId = listStr.get(0);
//									String lineType = listStr.get(1);
//									String ip = null;
//									if(listStr.size() >= 3){
//										ip = listStr.get(2);
//									}
//									//切换网络
//									
//									if(ip == null){
//										//直接写数据库
//										switchGatewayNetwork(linkId,lineType,ip);
//									} else {
//										boolean ping = PingIpUtils.ping(ip, 4, 50);
//										if(ping){
//											switchGatewayNetwork(linkId,lineType,ip);
//											
//										} else {
//											logger.error("网关切换失败，双线网络均不可达  key:" + gatewayStr);
//										}	
//									}
//									
//								}
//							});
//						}
//					}catch (Exception e){}
//					try {
//						Thread.sleep(100);
//					} catch (InterruptedException e) {}
//				}
//				
//			}
//		}).start();
	}
	


	private void scanGatewayNetwork() {
		Map<String, IGateLink> tempMap = AppStaticConfigs.simpleGateLinkRegister
				.getGateLinks();
		if (tempMap.size() > 0) {
			Iterator<String> it = tempMap.keySet().iterator();
			while (it.hasNext()) {
				String key = it.next();
				IGateLink igateLink = tempMap.get(key);
				SimpleGateLink simpleGateLink = null;
				if (igateLink instanceof SimpleGateLink) {
					simpleGateLink = (SimpleGateLink) igateLink;
				}
				if(simpleGateLink == null){
					continue;
				}
				
				String networkIpAddr = null;
				//获取key网络配置信息  1: 专线  2：互联网
				String networkType = AppStaticConfigs.gateSwitchMap.get(key);
				if(networkType == null){
					networkType = "1";
				}
				switch (networkType) {
				case "2":
					networkIpAddr = simpleGateLink.getGateDef().getInternetIp();
					break;
				case "1":
				default:
					networkIpAddr = simpleGateLink.getGateDef().getSpecialIp();
					break;
				}
				
				if(networkIpAddr == null){
					gatewaySwitchQueue.offer(key+":"+networkType);
					continue;
				}
				
				//检查IP是否能通PING
				//加入队列中进行异步查询
				String quereStr = key+":"+networkType+":"+networkIpAddr;
				pingQueue.offer(quereStr);

			}
		}
	}

	public boolean isKeepGoing() {
		return keepGoing;
	}

	public void setKeepGoing(boolean keepGoing) {
		this.keepGoing = keepGoing;
	}

	@Override
	public void destroy() {
		this.setKeepGoing(false);
		this.interrupt();
		stopPingTask();
		if(gatewayPool != null){
			gatewayPool.shutdown();
			gatewayPool = null;
		}
	}

	private void switchGatewayNetwork(String linkId, String lineType, String ip) {
		//写数据库
		String switchLineType =  "2".equals(lineType) ? "1" : "2";
		IGateLink igateLink = AppStaticConfigs.simpleGateLinkRegister.get(linkId);
		SimpleGateLink simpleGateLink = null;
		if (igateLink instanceof SimpleGateLink) {
			simpleGateLink = (SimpleGateLink) igateLink;
		}
		if(simpleGateLink == null){
			logger.error("无法识别的网关类型 " + linkId);
		}
		AppStaticConfigs.gateSwitchMap.put(linkId, switchLineType);
		ContextUtils.getBean2(GateSwitchDao.class).updateLineType(switchLineType, linkId);
		
		logger.info("切换网络成功  网关ID: "+ linkId + "   切换到   "+switchLineType +"网络");
		
		//写告警短信
		List<WarnRecv> users = AppStaticConfigs.warnRecvList;
		String mContent = AppStaticConfigs.smsTemplateMap.get(AppStaticConfigs.Const.SMS_TEMPLATE_TYPE_WGQH).getSmsContent();
		SmsWarnRecvMessage message = new SmsWarnRecvMessage(users,mContent,AppStaticConfigs.Const.SMS_TEMPLATE_TYPE_WGQH);
		
		WranSmsSocketTask.msgQueue.offer(message);
		logger.info("发送网络切换告警短信 ：" + message.toString());
	}
	
	
}
